#pragma once;

//define USE_LOG_FOR_DEBUG to enable log
//and use DEF_LOGFILE(szFileName) to instantiate a log object

#ifndef USE_LOG_FOR_DEBUG
#define DEF_LOGFILE(szFileName)
#endif

#ifdef USE_LOG_FOR_DEBUG
#include <io.h>
#include <time.h>
#include <fstream>
#include <string>
#include <tchar.h>
#include <Windows.h>

#define MAX_MSG_LEN	1024

#define DEF_LOGFILE(szFileName) CLog g_log(szFileName); 

class CLog{
public:
	CLog(const char* szFileName)
	{
		GenerateUniqueFileName(szFileName);
		m_out.open(m_szFileName.c_str());
	}
	~CLog()
	{
		m_out.close();
	}

	void Write(const char* pFormat, ...)
	{
		va_list args;
		va_start(args, pFormat);

		char szBuf[MAX_MSG_LEN];
		vsprintf_s(szBuf,MAX_MSG_LEN, pFormat, args);
		WriteStr(szBuf);
		va_end(args); 
	}

private:
	void WriteTime()
	{
		const int SIZE = 50;
		time_t ltime;
		char timebuf[SIZE];
		time( &ltime );
		ctime_s( timebuf, SIZE, &ltime);

		m_out<<"--"<<timebuf;
	}

	void WriteStr(const char* str)
	{
		m_WriteMutex.Lock();
		if(m_out.is_open())
		{
			WriteTime();
			m_out<<str<<std::endl;		
		}
		m_WriteMutex.UnLock();
	}

	void GenerateUniqueFileName(const char* szFileName)
	{
		char templateStr[] = "XXXXXX";
		int iLen = sizeof(templateStr)+4;
		char* szRet = new char[iLen];
		strcpy_s(szRet, iLen, templateStr);

		if (szRet!=0 && _mktemp_s(szRet, sizeof(templateStr))==0)
		{
			m_szFileName = GetModulePath() + "\\" + std::string(szRet) + szFileName;
		}
		else 
		{
			m_szFileName = GetModulePath() + "\\" + szFileName;
		}

		delete szRet;
	}


	std::string GetModulePath()
	{
		char szModulePath[MAX_PATH]; 

		if(!GetModuleFileName( NULL, szModulePath, MAX_PATH ))
			return _T("");

		static const std::string::size_type npos = -1;
		std::string str(szModulePath);
		size_t pos = str.find_last_of("\\/");

		std::string path;
		if(pos != npos){
			path = str.substr(0, pos);
		}

		return path;
	}


	std::string m_szFileName;
	std::ofstream m_out;

	class CLogMutex
	{
	private:
		CRITICAL_SECTION mutex_;
		// = Disallow copying and assignment.
		CLogMutex (const CLogMutex &);
		void operator= (const CLogMutex &);

	public:
		CLogMutex (void)	{InitializeCriticalSection (&mutex_);}
		~CLogMutex (void)	{DeleteCriticalSection (&mutex_);}
		void Lock (void)	{EnterCriticalSection (&mutex_); }
		void UnLock (void)	{LeaveCriticalSection (&mutex_); }
	};

	CLogMutex m_WriteMutex;

};

extern CLog g_log;

inline void WriteLog(const char* pFormat, ...)
{
	va_list args;
	va_start(args, pFormat);

	char szBuf[MAX_MSG_LEN];
	vsprintf_s(szBuf,MAX_MSG_LEN, pFormat, args);
	g_log.Write(szBuf);
	va_end(args); 

}

#endif	//end #ifdef USE_LOG_FOR_DEBUG

#ifdef USE_LOG_FOR_DEBUG
#define WRITE_LOG	WriteLog
#else
#define WRITE_LOG	__noop
#endif